﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Api.Model;

namespace Core.Model.Test.Unit
{
    [TestFixture]
    public class ArticlesModelTests
    {
        ArticlesModel articlesModel;

        [SetUp]
        public void Setup()
        {
            articlesModel = new ArticlesModel();
        }

        [Test]
        public void AreArticlesLoaded_AddArticlesNotCalled_AreArticlesLoadedFalse()
        {
            Assert.False(articlesModel.AreArticlesLoaded);
        }

        [Test]
        public void AreArticlesLoaded_AddArticlesCalled_AreArticlesLoadedTrue()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() });

            Assert.True(articlesModel.AreArticlesLoaded);
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetArticles_AddArticlesNotCalled_ThrowsInvalidOperationException()
        {
            articlesModel.GetArticles();
        }

        [Test]
        public void GetArticles_AddArticlesCalled_ReturnsArticles()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() });

            var articles = articlesModel.GetArticles();

            Assert.IsTrue(articles.Count() > 0);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddArticless_ArgumentsNull_ThrowArgumentNullException()
        {
            articlesModel.AddArticles(null);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void AddArticless_ArgumentsEmpty_ThrowArgumentException()
        {
            articlesModel.AddArticles(Enumerable.Empty<Article>());
        }

        [Test]
        public void AddArticless_ArgumentsNotEmpty_ExceptionNotThrown()
        {
            Assert.DoesNotThrow(() =>
            {
                articlesModel.AddArticles(new List<Article>() { new Article() });
            });
        }

        [Test]
        public void GetArticles_AddArticlesCalled_ReturnsProperArticlesCount()
        {
            articlesModel.AddArticles(new List<Article>() { new Article(), new Article(), new Article() });

            var articles = articlesModel.GetArticles();

            Assert.AreEqual(3, articles.Count());
        }

        [Test]
        public void GetArticles_AddArticlesCalledTwice_ReturnsProperArticlesCount()
        {
            articlesModel.AddArticles(new List<Article>() { new Article(), new Article(), new Article() });
            articlesModel.AddArticles(new List<Article>() { new Article(), new Article() });

            var articles = articlesModel.GetArticles();

            Assert.AreEqual(5, articles.Count());
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetTags_AddArticlesNotCalled_ThrowInvalidOperation()
        {
            articlesModel.GetTags();
        }

        [Test]
        [ExpectedException(typeof(InvalidOperationException))]
        public void GetTags_AddArticlesCalledNoArticleContainsTags_ThrowInvalidOperation()
        {
            articlesModel.AddArticles(new List<Article>() { new Article(), new Article(), new Article() });

            articlesModel.GetTags();
        }

        [Test]
        public void AreTagsAvailable_AddArticlesNotCalled_ReturnsFalse()
        {
            Assert.False(articlesModel.AreTagsAvailable);
        }

        [Test]
        public void AreTagsAvailable_AddArticlesCalledNoArticleContainsTags_ReturnsFalse()
        {
            articlesModel.AddArticles(new List<Article>() { new Article(), new Article(), new Article() });

            Assert.False(articlesModel.AreTagsAvailable);
        }

        [Test]
        public void AreTagsAvailable_AddArticlesCalledArticlesContainsOneTag_ReturnsTrue()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() { Tags = new List<Tag>() { new Tag() { Name = "Rss" } } } });

            Assert.True(articlesModel.AreTagsAvailable);
        }

        [Test]
        public void AreTagsAvailable_AddArticlesCalledArticlesContainsManyTags_ReturnsTrue()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() { Tags = new List<Tag>() { new Tag() { Name = "Rss" } } } });

            Assert.True(articlesModel.AreTagsAvailable);
        }

        [Test]
        public void GetTags_AddArticlesCalledArticlesContainsOneTag_OneTagIsReturned()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() { Tags = new List<Tag>() { new Tag() { Name = "Rss" } } } });

            var tags = articlesModel.GetTags();

            Assert.AreEqual(1, tags.Count());
        }

        [Test]
        public void GetTags_AddArticlesCalledArticlesContainsManyTags_ManyTagsAreReturned()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() { Tags = new List<Tag>()
            {
                new Tag() { Name = "Rss" },
                new Tag() { Name = "Twitter" },
                new Tag() { Name = "Facebook" },
            } } });

            var tags = articlesModel.GetTags();

            Assert.AreEqual(3, tags.Count());
        }

        [Test]
        public void GetTags_ArticlesContainsManySameTags_DistinctTagsAreReturned()
        {
            articlesModel.AddArticles(new List<Article>() { new Article() { Tags = new List<Tag>()
            {
                new Tag() { Name = "Rss" },
                new Tag() { Name = "Rss" },
                new Tag() { Name = "Adult" },
                new Tag() { Name = "Facebook" },
                new Tag() { Name = "Rss" },
                new Tag() { Name = "OtherTag" },
                new Tag() { Name = "Facebook" },
                new Tag() { Name = "Twitter" },
                new Tag() { Name = "Rss" },
                new Tag() { Name = "Facebook" },
            } } });

            var tags = articlesModel.GetTags();

            Assert.AreEqual(5, tags.Count());
        }
    }
}
